define('topology', function(require) {
  'use strict';

  var zrender = require('zrender');
  var Group = require('zrender/Group');
  var Polyline = require('zrender/shape/Polyline');
  var Rectangle = require('zrender/shape/Rectangle');
  var IsogonShape = require('zrender/shape/Isogon');

  var topology = {
    init: init
  };

  function init(dom) {
    var topo = new Topology(dom);
    return topo;
  }

  function Topology(dom) {
    this.zrender = zrender.init(dom);
    this.zrender.modLayer(0, { zoomable: true, panable: true });
  }

  Topology.prototype.create = function(data) {
    var group = new Group({ position: [0, 0] });
    makeVectorLines(this, group, data);
    makeGraph(this, group, data);
    this.zrender.addGroup(group);
    this.zrender.render();
  };

  Topology.prototype.on = function(eventClass, callback) {
    if (eventClass === 'click') {
      this.onclick = callback;
    }
  };

  function makeGraph(topology, group, data) {
    _.forEach(data, function(node) {
      var title = node.text.title;
      var hoverTextColor = node.text.hover.color;
      var hoverBgColor = node.bg.hover.color;
      var graph = new Rectangle({
        nodeData: node.nodeData,
        style: {
          x: node.x,
          y: node.y,
          width: node.width,
          height: node.height,
          radius: 2,
          brushType: 'both',
          color: node.bg.color,
          lineWidth: 0,
          shadowColor: '#a5b9cc',
          shadowBlur: 3,
          shadowOffsetY: 1,
          text: node.text.value,
          title: node.text.title,
          textColor: node.text.color,
          textFont: 'normal 10px 微软雅黑',
          textPosition: 'inside',
          textAlign: 'center',
          textBaseline: 'middle',
        },
        highlightStyle: {
          lineWidth: 0,
          x: node.x - 3,
          y: node.y - 3,
          width: node.width + 6,
          height: node.height + 6,
          color: node.bg.hover.color,
          textColor: node.text.hover.color,
        },
        // draggable: true,
        onmousedown: function(params) {
          if (topology.onclick) {
            topology.onclick(params);
          }
        },
        onmouseover: function(params) {
          if (!params.target.toolTip) {
            params.target.toolTip = makeToolTip(group, params, 'followNode');
            topology.zrender.refresh();
          }
        },
        onmouseout: function(params) {
          if (params.target.toolTip) {
            group.removeChild(params.target.toolTip);
            topology.zrender.refresh();
            params.target.toolTip = undefined;
          }
        }
      });
      group.addChild(graph);
    });
  }

  function makeToolTip(group, params, follow) {


    var charPixelWidth = 11;
    var width = 120;
    var height = 30;
    var title = params.target.style.title;
    var x, y;
    var offsetx = 0;

    if (follow === 'followMouse') {
      width = 120;
      x = params.event.layerX;
      y = params.event.layerY - 100;
      offsetx = 0;
    } else if (follow === 'followNode') {
      width = params.target.style.width;
      x = params.target.style.x;
      y = params.target.style.y - params.target.style.height - 20;
      offsetx = width / 2;
    }

    if (title.length * charPixelWidth < width) {

    } else if (title.length * charPixelWidth < 400) {
      width = title.length * charPixelWidth;
      x = x + offsetx - width / 2;
    } else {
      title = _.join(su.chunk(title, 400 / charPixelWidth), '\n');
      width = 400;
      height = 30 + 12 * (title.length / (400 / charPixelWidth) - 1);
      y = y - height + 30;
      x = x + offsetx - 400 / 2;
    }

    var toolTip = new Rectangle({
      hoverable: false,
      z: 9999999,
      style: {
        x: x,
        y: y,
        width: width,
        height: height,
        radius: [5, 5],
        brushType: 'fill',
        color: '#1f1f1f',
        text: title,
        textColor: '#fff',
        textPosition: 'inside',
        textAlign: 'center',
        textBaseline: 'middle',
        opacity: '0.9'
      }
    });
    group.addChild(toolTip);
    return toolTip;
  }

  function makeVectorLines(topology, group, data) {
    var sourceNode, targetNode;
    _.forEach(data, function(node) {
      _.forEach(node.sourceNodeIds, function(sourceNodeId) {
        sourceNode = _.find(data, { nodeId: sourceNodeId });
        targetNode = node;
        makeLine(topology, group, sourceNode, targetNode);
      });

      _.forEach(node.targetNodeIds, function(targetNodeId) {
        sourceNode = node;
        targetNode = _.find(data, { nodeId: targetNodeId });
        makeLine(topology, group, sourceNode, targetNode);
      });
    });
  }

  function makeLine(topology, group, sourceNode, targetNode) {
    var arrowRadius = 5,
      borderWidth = 2;
    var xStart = 0,
      yStart = 0,
      xEnd = 0,
      yEnd = 0,
      arrowX = 0,
      arrowY = 0,
      arrowRotation = 0;
    if (sourceNode && targetNode) {
      if (sourceNode.y > targetNode.y) {
        xStart = sourceNode.x + sourceNode.width / 2;
        yStart = sourceNode.y;
        xEnd = targetNode.x + targetNode.width / 2;
        yEnd = targetNode.y + targetNode.height;

        arrowX = xEnd;
        arrowY = yEnd + arrowRadius / 2 + borderWidth;
        arrowRotation = 0;
      } else if (sourceNode.y < targetNode.y) {
        xStart = sourceNode.x + sourceNode.width / 2;
        yStart = sourceNode.y + sourceNode.height;
        xEnd = targetNode.x + targetNode.width / 2;
        yEnd = targetNode.y;

        arrowX = xEnd;
        arrowY = yEnd - arrowRadius / 2 - borderWidth;
        arrowRotation = 1.04;
      } else if (sourceNode.x > targetNode.x) {
        xStart = sourceNode.x;
        yStart = sourceNode.y + sourceNode.height / 2;
        xEnd = targetNode.x + targetNode.width;
        yEnd = targetNode.y + targetNode.height / 2;

        arrowX = xEnd + arrowRadius / 2 + borderWidth;
        arrowY = yEnd;
        arrowRotation = 1.58;
      } else if (sourceNode.x < targetNode.x) {
        xStart = sourceNode.x + sourceNode.width;
        yStart = sourceNode.y + sourceNode.height / 2;
        xEnd = targetNode.x;
        yEnd = targetNode.y + targetNode.height / 2;

        arrowX = xEnd - arrowRadius / 2 - borderWidth;
        arrowY = yEnd;
        arrowRotation = 0.52;
      } else {
        return;
      }

      var line = new Polyline({
        style: {
          pointList: [
            [xStart, yStart],
            [xStart, yStart + ((yEnd - yStart) / 6)],
            [xEnd, yEnd - ((yEnd - yStart) / 4)],
            [xEnd, yEnd]
          ],
          strokeColor: '#777',
          lineWidth: 1
        },
        highlightStyle: {
          strokeColor: '#f90',
          lineWidth: 2
        },
        onmouseover: function(params) {
          if (!params.target.toolTip) {
            var data = {
              event: {
                layerX: params.event.layerX,
                layerY: params.event.layerY
              },
              target: {
                style: {
                  title: sourceNode.text.title + ' > ' + targetNode.text.title
                }
              }
            };
            params.target.toolTip = makeToolTip(group, data, 'followMouse');
            topology.zrender.refresh();
          }
        },
        onmouseout: function(params) {
          if (params.target.toolTip) {
            group.removeChild(params.target.toolTip);
            topology.zrender.refresh();
            params.target.toolTip = undefined;
          }
        }
      });
      group.addChild(line);

      var arrow = new IsogonShape({
        style: {
          x: arrowX,
          y: arrowY,
          r: arrowRadius,
          n: 3,
          color: '#777',
          lineWidth: 0,
        },
        rotation: [arrowRotation, arrowX, arrowY],
      });
      group.addChild(arrow);
    }
  }

  return topology;
});